﻿Imports System
Imports System.CodeDom
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Reflection
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.Activities.Rules
    <AttributeUsage((AttributeTargets.Property Or AttributeTargets.Method), AllowMultiple:=True)> _
    Public NotInheritable Class RuleInvokeAttribute
        Inherits RuleAttribute
        ' Methods
        Public Sub New(ByVal methodInvoked As String)
            Me.methodInvoked = methodInvoked
        End Sub

        Friend Overrides Sub Analyze(ByVal analysis As RuleAnalysis, ByVal member As MemberInfo, ByVal targetExpression As CodeExpression, ByVal targetQualifier As RulePathQualifier, ByVal argumentExpressions As CodeExpressionCollection, ByVal parameters As ParameterInfo(), ByVal attributedExpressions As List([Of] CodeExpression))
            Dim methodStack As New Stack([Of] MemberInfo)
            methodStack.Push(member)
            Me.AnalyzeInvokeAttribute(analysis, member.DeclaringType, methodStack, targetExpression, targetQualifier, argumentExpressions, parameters, attributedExpressions)
            methodStack.Pop
        End Sub

        Private Sub AnalyzeInvokeAttribute(ByVal analysis As RuleAnalysis, ByVal contextType As Type, ByVal methodStack As Stack([Of] MemberInfo), ByVal targetExpression As CodeExpression, ByVal targetQualifier As RulePathQualifier, ByVal argumentExpressions As CodeExpressionCollection, ByVal parameters As ParameterInfo(), ByVal attributedExpressions As List([Of] CodeExpression))
            Dim info As MemberInfo
            For Each info In contextType.GetMember(Me.methodInvoked, (MemberTypes.Property Or MemberTypes.Method), (BindingFlags.FlattenHierarchy Or (BindingFlags.NonPublic Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))))
                If Not methodStack.Contains(info) Then
                    methodStack.Push(info)
                    Dim customAttributes As Object() = info.GetCustomAttributes(GetType(RuleAttribute), True)
                    If ((Not customAttributes Is Nothing) AndAlso (customAttributes.Length <> 0)) Then
                        Dim attribute As RuleAttribute
                        For Each attribute In DirectCast(customAttributes, RuleAttribute())
                            Dim attribute2 As RuleReadWriteAttribute = [TryCast](attribute,RuleReadWriteAttribute)
                            If (Not attribute2 Is Nothing) Then
                                attribute2.Analyze(analysis, info, targetExpression, targetQualifier, argumentExpressions, parameters, attributedExpressions)
                            Else
                                DirectCast(attribute, RuleInvokeAttribute).AnalyzeInvokeAttribute(analysis, contextType, methodStack, targetExpression, targetQualifier, argumentExpressions, parameters, attributedExpressions)
                            End If
                        Next
                    End If
                    methodStack.Pop
                End If
            Next
        End Sub

        Friend Overrides Function Validate(ByVal validation As RuleValidation, ByVal member As MemberInfo, ByVal contextType As Type, ByVal parameters As ParameterInfo()) As Boolean
            Dim methodStack As New Stack([Of] MemberInfo)
            methodStack.Push(member)
            Dim flag As Boolean = Me.ValidateInvokeAttribute(validation, member, contextType, methodStack)
            methodStack.Pop
            Return flag
        End Function

        Private Function ValidateInvokeAttribute(ByVal validation As RuleValidation, ByVal member As MemberInfo, ByVal contextType As Type, ByVal methodStack As Stack([Of] MemberInfo)) As Boolean
            Dim error As ValidationError
            If String.IsNullOrEmpty(Me.methodInvoked) Then
                [error] = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.AttributeMethodNotFound, New Object() { member.Name, MyBase.GetType.Name, Messages.NullValue }), &H56B, True)
                [error].UserData.Item("ErrorObject") = Me
                validation.AddError([error])
                Return False
            End If
            Dim flag As Boolean = True
            Dim infoArray As MemberInfo() = contextType.GetMember(Me.methodInvoked, (MemberTypes.Property Or MemberTypes.Method), (BindingFlags.FlattenHierarchy Or (BindingFlags.NonPublic Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))))
            If ((infoArray Is Nothing) OrElse (infoArray.Length = 0)) Then
                [error] = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.AttributeMethodNotFound, New Object() { member.Name, MyBase.GetType.Name, Me.methodInvoked }), &H56B, True)
                [error].UserData.Item("ErrorObject") = Me
                validation.AddError([error])
                Return False
            End If
            Dim i As Integer
            For i = 0 To infoArray.Length - 1
                Dim item As MemberInfo = infoArray(i)
                If Not methodStack.Contains(item) Then
                    methodStack.Push(item)
                    Dim customAttributes As Object() = item.GetCustomAttributes(GetType(RuleAttribute), True)
                    If ((Not customAttributes Is Nothing) AndAlso (customAttributes.Length <> 0)) Then
                        Dim attribute As RuleAttribute
                        For Each attribute In customAttributes
                            Dim attribute2 As RuleReadWriteAttribute = [TryCast](attribute,RuleReadWriteAttribute)
                            If (Not attribute2 Is Nothing) Then
                                If (attribute2.Target = RuleAttributeTarget.Parameter) Then
                                    [error] = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.InvokeAttrRefersToParameterAttribute, New Object() { item.Name }), &H1A5, True)
                                    [error].UserData.Item("ErrorObject") = Me
                                    validation.AddError([error])
                                    flag = False
                                Else
                                    attribute2.Validate(validation, item, contextType, Nothing)
                                End If
                            Else
                                DirectCast(attribute, RuleInvokeAttribute).ValidateInvokeAttribute(validation, item, contextType, methodStack)
                            End If
                        Next
                    End If
                    methodStack.Pop
                End If
            Next i
            Return flag
        End Function


        ' Properties
        Public ReadOnly Property MethodInvoked As String
            Get
                Return Me.methodInvoked
            End Get
        End Property


        ' Fields
        Private methodInvoked As String
    End Class
End Namespace

